import socket
import threading
import sys


def forward_data(source_sock, dest_sock):
    try:
        while True:
            data = source_sock.recv(4096)
            if not data:
                break
            dest_sock.send(data)
    except (ConnectionResetError, BrokenPipeError, socket.error):
        pass
    finally:
        source_sock.close()
        dest_sock.close()


def handle_client(client_sock, target_host, target_port):
    try:
        # 创建到IPv6目标的socket
        target_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
        target_sock.connect((target_host, target_port))

        # 启动两个线程分别处理双向数据流
        threading.Thread(
            target=forward_data,
            args=(client_sock, target_sock),
            daemon=True
        ).start()

        threading.Thread(
            target=forward_data,
            args=(target_sock, client_sock),
            daemon=True
        ).start()

    except socket.error as e:
        print(f"连接目标错误: {e}")
        client_sock.close()
        if 'target_sock' in locals():
            target_sock.close()


def start_proxy(listen_host, listen_port, target_host, target_port):
    # 创建IPv4监听socket
    listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    try:
        listen_sock.bind((listen_host, listen_port))
        listen_sock.listen(5)
        print(f"转发服务已启动，监听 {listen_host}:{listen_port}，转发至 [{target_host}]:{target_port}")

        while True:
            client_sock, client_addr = listen_sock.accept()
            print(f"接受来自 {client_addr} 的连接")

            # 为新连接创建处理线程
            threading.Thread(
                target=handle_client,
                args=(client_sock, target_host, target_port),
                daemon=True
            ).start()

    except KeyboardInterrupt:
        print("\n服务器正在关闭...")
    except socket.error as e:
        print(f"Socket错误: {e}")
    finally:
        listen_sock.close()


if __name__ == "__main__":

    listen_host = '0.0.0.0'
    listen_port = 12345
    target_host = '[::1]'
    target_port = 12345

    start_proxy(listen_host, listen_port, target_host, target_port)
